package task

import (
	"context"
	"fmt"
	"sync"
	"time"

	probePb "probe-scheduler/pb/probe"
	pb "probe-scheduler/pb/scheduler"

	"github.com/robfig/cron/v3"
)

// 任务信息结构体，包含任务配置和调度信息
type TaskInfo struct {
	Task    *pb.Task     // 任务配置
	EntryID cron.EntryID // cron条目ID
	Paused  bool         // 是否暂停
}

// Scheduler 任务调度器
type Scheduler struct {
	cron       *cron.Cron
	executor   *Executor
	resultChan chan *pb.TaskResult
	taskMap    map[int64]*TaskInfo // 任务ID -> 任务信息
	mu         sync.RWMutex
}

// NewScheduler 创建调度器实例
func NewScheduler(cron *cron.Cron, resultChan chan *pb.TaskResult, probeClient probePb.ProbeServiceClient) *Scheduler {
	return &Scheduler{
		cron:       cron,
		executor:   NewExecutor(probeClient, resultChan),
		resultChan: resultChan,
		taskMap:    make(map[int64]*TaskInfo),
	}
}

// Start 启动调度器
func (s *Scheduler) Start() {
	s.cron.Start()
}

// CreateTask 创建并调度任务
func (s *Scheduler) CreateTask(ctx context.Context, task *pb.Task) (int64, error) {
	// 检查任务是否已存在
	s.mu.RLock()
	_, exists := s.taskMap[task.Id]
	s.mu.RUnlock()
	if exists {
		return 0, fmt.Errorf("task %d already exists", task.Id)
	}

	// 设置初始状态
	task.Status = pb.TaskStatus_SCHEDULED

	// 创建执行函数
	// 使用背景上下文而不是传入的ctx，避免外部取消影响任务执行
	taskCtx := context.Background()
	execFunc := func() {
		s.executor.Execute(taskCtx, task)
	}

	var entryID cron.EntryID
	var err error
	var taskInfo *TaskInfo

	switch task.Type {
	case pb.TaskType_IMMEDIATE:
		// 立即执行任务
		go execFunc()
		// 立即任务执行后状态设为已完成
		task.Status = pb.TaskStatus_STOPPED
		taskInfo = &TaskInfo{
			Task:   task,
			Paused: false,
		}

	case pb.TaskType_CRON:
		// 定时任务
		if task.CronExpression == "" {
			return 0, fmt.Errorf("cron task requires cron_expression")
		}
		entryID, err = s.cron.AddFunc(task.CronExpression, execFunc)
		taskInfo = &TaskInfo{
			Task:    task,
			EntryID: entryID,
			Paused:  false,
		}

	case pb.TaskType_RECURRING:
		// 循环任务
		if task.Interval <= 0 {
			return 0, fmt.Errorf("recurring task requires interval > 0")
		}
		// 转换为cron表达式（秒级）
		cronExpr := fmt.Sprintf("*/%d * * * * *", task.Interval)
		entryID, err = s.cron.AddFunc(cronExpr, execFunc)
		taskInfo = &TaskInfo{
			Task:    task,
			EntryID: entryID,
			Paused:  false,
		}

	case pb.TaskType_PERIODIC:
		// 周期定时循环任务
		if task.CronExpression == "" || task.StartTime <= 0 || task.EndTime <= 0 || task.StartTime >= task.EndTime {
			return 0, fmt.Errorf("invalid periodic task parameters")
		}
		// 包装执行函数，增加周期判断
		wrappedFunc := func() {
			now := time.Now().Unix()
			if now >= task.StartTime && now <= task.EndTime {
				execFunc()
			} else if now > task.EndTime {
				// 超出周期自动停止
				s.DeleteTask(task.Id)
			}
		}
		entryID, err = s.cron.AddFunc(task.CronExpression, wrappedFunc)
		taskInfo = &TaskInfo{
			Task:    task,
			EntryID: entryID,
			Paused:  false,
		}

	default:
		return 0, fmt.Errorf("unsupported task type: %v", task.Type)
	}

	if err != nil {
		return 0, fmt.Errorf("failed to schedule task: %v", err)
	}

	// 记录任务
	s.mu.Lock()
	s.taskMap[task.Id] = taskInfo
	s.mu.Unlock()

	return task.Id, nil
}

// DeleteTask 停止并删除任务
func (s *Scheduler) DeleteTask(taskID int64) error {
	s.mu.RLock()
	taskInfo, exists := s.taskMap[taskID]
	s.mu.RUnlock()

	if !exists {
		return fmt.Errorf("task %d not found", taskID)
	}

	// 从cron中移除（如果不是立即执行任务）
	if taskInfo.Task.Type != pb.TaskType_IMMEDIATE && !taskInfo.Paused {
		s.cron.Remove(taskInfo.EntryID)
	}

	// 从映射中删除
	s.mu.Lock()
	delete(s.taskMap, taskID)
	s.mu.Unlock()

	return nil
}

// UpdateTask 更新任务配置
func (s *Scheduler) UpdateTask(ctx context.Context, task *pb.Task) error {
	if task.Id == 0 {
		return fmt.Errorf("task id is required")
	}

	// 先删除旧任务
	if err := s.DeleteTask(task.Id); err != nil && err.Error() != fmt.Sprintf("task %d not found", task.Id) {
		return err
	}

	// 再创建新任务
	_, err := s.CreateTask(ctx, task)
	return err
}

// QueryTasks 查询任务
func (s *Scheduler) QueryTasks(taskID int64, status []pb.TaskStatus) ([]*pb.Task, int) {
	s.mu.RLock()
	defer s.mu.RUnlock()

	var tasks []*pb.Task

	// 筛选状态
	statusMap := make(map[pb.TaskStatus]bool)
	for _, s := range status {
		statusMap[s] = true
	}

	// 如果指定了任务ID，优先查询单个任务
	if taskID != 0 {
		if taskInfo, exists := s.taskMap[taskID]; exists {
			// 检查状态是否匹配
			if len(status) == 0 || statusMap[taskInfo.Task.Status] {
				tasks = append(tasks, taskInfo.Task)
			}
		}
		return tasks, len(tasks)
	}

	// 查询所有任务
	for _, taskInfo := range s.taskMap {
		// 检查状态是否匹配
		if len(status) == 0 || statusMap[taskInfo.Task.Status] {
			tasks = append(tasks, taskInfo.Task)
		}
	}

	return tasks, len(tasks)
}

// PauseTask 暂停任务
func (s *Scheduler) PauseTask(taskID int64) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	taskInfo, exists := s.taskMap[taskID]
	if !exists {
		return fmt.Errorf("task %d not found", taskID)
	}

	if taskInfo.Paused {
		return fmt.Errorf("task %d is already paused", taskID)
	}

	// 立即执行任务不能暂停
	if taskInfo.Task.Type == pb.TaskType_IMMEDIATE {
		return fmt.Errorf("cannot pause immediate tasks")
	}

	// 从cron中移除（停止执行）
	s.cron.Remove(taskInfo.EntryID)
	taskInfo.Paused = true
	taskInfo.Task.Status = pb.TaskStatus_PAUSED
	s.taskMap[taskID] = taskInfo

	return nil
}

// ResumeTask 恢复任务执行
func (s *Scheduler) ResumeTask(ctx context.Context, taskID int64) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	taskInfo, exists := s.taskMap[taskID]
	if !exists {
		return fmt.Errorf("task %d not found", taskID)
	}

	if !taskInfo.Paused {
		return fmt.Errorf("task %d is not paused", taskID)
	}

	// 创建执行函数
	execFunc := func() {
		s.executor.Execute(ctx, taskInfo.Task)
	}

	var entryID cron.EntryID
	var err error

	// 根据任务类型重新添加到cron
	switch taskInfo.Task.Type {
	case pb.TaskType_CRON:
		entryID, err = s.cron.AddFunc(taskInfo.Task.CronExpression, execFunc)

	case pb.TaskType_RECURRING:
		cronExpr := fmt.Sprintf("*/%d * * * * *", taskInfo.Task.Interval)
		entryID, err = s.cron.AddFunc(cronExpr, execFunc)

	case pb.TaskType_PERIODIC:
		wrappedFunc := func() {
			now := time.Now().Unix()
			if now >= taskInfo.Task.StartTime && now <= taskInfo.Task.EndTime {
				execFunc()
			} else if now > taskInfo.Task.EndTime {
				s.DeleteTask(taskID)
			}
		}
		entryID, err = s.cron.AddFunc(taskInfo.Task.CronExpression, wrappedFunc)

	default:
		return fmt.Errorf("cannot resume task type: %v", taskInfo.Task.Type)
	}

	if err != nil {
		return fmt.Errorf("failed to resume task: %v", err)
	}

	// 更新任务信息（恢复运行）
	taskInfo.EntryID = entryID
	taskInfo.Paused = false
	taskInfo.Task.Status = pb.TaskStatus_SCHEDULED
	s.taskMap[taskID] = taskInfo

	return nil
}
